package com.bestcem.xm.wallet.controller;

import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.EmailUtil;
import com.bestcem.xm.component.security.annotation.XmAuth;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.component.security.dto.TokenDTO;
import com.bestcem.xm.user.enums.NotifyStatusEnum;
import com.bestcem.xm.user.enums.NotifyTypeEnum;
import com.bestcem.xm.user.mq.message.user.SmsMessage;
import com.bestcem.xm.user.service.UserMqConsumeService;
import com.bestcem.xm.user.util.business.DataBaseUtil;
import com.bestcem.xm.wallet.constant.CommonConstant;
import com.bestcem.xm.wallet.controller.vo.request.ApplyInvoiceRequestVO;
import com.bestcem.xm.wallet.controller.vo.request.LimitRechargeVO;
import com.bestcem.xm.wallet.controller.vo.request.WalletRechargeRequestVO;
import com.bestcem.xm.wallet.controller.vo.response.*;
import com.bestcem.xm.wallet.enums.*;
import com.bestcem.xm.wallet.grpc.client.*;
import com.bestcem.xm.wallet.grpc.client.dto.*;
import com.bestcem.xm.wallet.service.LimitOrderService;
import com.bestcem.xm.wallet.service.dto.LimitOrderDTO;
import com.bestcem.xm.wallet.service.dto.MiniProgramPayDTO;
import com.bestcem.xm.wallet.service.dto.WalletRechargeInfoDTO;
import com.bestcem.xm.wallet.util.WalletAsyncUtil;
import com.bestcem.xm.wallet.util.business.EnvSettingUtil;
import com.bestcem.xm.wallet.util.business.MailUtil;
import com.bestcem.xm.wallet.util.convert.LimitOrderConvert;
import com.bestcem.xm.wallet.util.convert.WalletWalletConvert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 用户企业钱包服务提供
 *
 * @author qiongyu.cui <qiongyu.cui@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/17 22:20
 */
@Slf4j
@RestController
@RequestMapping(value = "/wallet")
public class UserWalletController {

    @Resource
    private LimitOrderConvert limitOrderConvert;

    @Resource
    private WalletWalletGrpcService walletWalletGrpcService;

    @Resource
    private WalletSmsBalanceGrpcService walletSmsBalanceGrpcService;

    @Resource
    private WalletExpenseGrpcService walletExpenseGrpcService;

    @Resource
    private WalletInvoiceGrpcService walletInvoiceGrpcService;

    @Resource
    private WalletBaseUserGrpcService walletBaseUserGrpcService;

    @Resource
    private MailUtil mailUtil;

    @Resource
    private WalletWalletConvert walletWalletConvert;

    @Resource
    private LimitOrderService limitOrderService;

    @Resource
    private EnvSettingUtil envSettingUtil;
    @Resource
    private WalletAsyncUtil walletAsyncUtil;

    @Resource
    private WalletOmUserGrpcService walletOmUserGrpcService;

    @Resource
    private UserMqConsumeService userMqConsumeService;

    //@Resource
    //private UserMessageSender userMessageSender;

    /**
     * 分页查询企业钱包明细列表
     * apps_mysql.wallet.v2.wallet.handlers.CorporateWalletRecordsHandler
     * python引用：apps_mysql.wallet.v2.wallet.handlers.CorporateWalletRecordsHandler
     * * - “@decorators.render_json“
     * * - ”@decorators.permission”
     *
     * @param ttype    交易明细类型
     * @param page     第几页，默认不传第一页
     * @param pageSize 每页大小，默认不传为10
     * @return com.bestcem.xm.util.XmResultJson
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/18 16:40
     */
    @GetMapping("/corporate_wallet/records/")
    public XmResultJson<PageResponseVO<FinanceRecordsResponseVO>> corporateWalletRecords(
            @RequestParam(value = "ttype", required = false) Integer ttype, @RequestParam("page") Integer page,
            @RequestParam("rowsPerPage") Integer pageSize) {
        // 获取当前的登录信息
        TokenDTO currentToken = SecurityContextHolder.getToken();
        // 根据orgId查询租户的企业钱包id
        OrganizationDTO organization = walletBaseUserGrpcService.getOrganization(currentToken.getOrgId());
        if (Objects.isNull(organization)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应租户下的企业钱包id信息");
        }
        String walletId = organization.getCorpWallet();
        ListFinanceDTO listFinanceDTO = walletWalletGrpcService.listFinanceRecords(page, pageSize, walletId, ttype);
        if (Objects.isNull(listFinanceDTO)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应钱包下的明细信息");
        }

        // 转换结果
        PageResponseVO<FinanceRecordsResponseVO> response = new PageResponseVO<>();
        response.setTotal((long) listFinanceDTO.getTotal());
        response.setRows(walletWalletConvert.financeDtos2Vos(listFinanceDTO.getFinanceRecords()));
        return XmResultJson.success(response);
    }

    /**
     * 查询剩余可使用余额
     *
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/18 18:03
     */
    @GetMapping("/corporate_wallet/balance/")
    @XmAuth
    public XmResultJson<GetWalletBalanceVO> getWalletBalance() {
        /*// 获取当前的登录信息
        TokenDTO currentToken = SecurityContextHolder.getToken();
        // 根据orgId查询租户的企业钱包id
        OrganizationDTO organization = walletBaseUserGrpcService.getOrganization(currentToken.getOrgId());
        if (Objects.isNull(organization)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应租户下的企业钱包id信息");
        }

        if (StringUtils.isBlank(organization.getCorpWallet())) {
            OrgCreateMessage message = new OrgCreateMessage();
            message.setOrgId(organization.getOrgId());
            userMqConsumeService.orgCreateMessageListener(message);
        }

        // 根据orgId查询WalletInfoDTO
        WalletInfoDTO walletInfoDTO = walletWalletGrpcService.getWallet(organization.getCorpWallet());
        if (Objects.isNull(walletInfoDTO)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.THIRD_PART, "获取钱包信息失败");
        }

        // 根据orgId查询SmsTaskInfoDTO
        SmsBalanceDTO smsBalanceByOrgId = walletSmsBalanceGrpcService.getSmsBalanceByOrgId(currentToken.getOrgId());
        if (Objects.isNull(smsBalanceByOrgId)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.THIRD_PART, "企业钱包获取短信余额请求失败");
        }

        GetWalletBalanceVO walletBalanceVO = new GetWalletBalanceVO();
        walletBalanceVO.setSmsPrice(Integer.valueOf(organization.getSmsPrice()))
                .setFreeNum(smsBalanceByOrgId.getBalance())
                .setBalance(walletInfoDTO.getBalance());
        return XmResultJson.success(walletBalanceVO);*/
        return XmResultJson.success(new GetWalletBalanceVO(994140, 67, 9));
    }

    /**
     * 企业钱包-余额-【红包占用、短信占用】
     *
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/20 18:35
     */
    @GetMapping("/corporate_wallet/freeze/")
    public XmResultJson<List<WalletFreezeInfoVO>> getWalletFreeze() {
        // 获取当前的登录信息
        TokenDTO currentToken = SecurityContextHolder.getToken();
        // 根据orgId查询租户的企业钱包id
        OrganizationDTO organization = walletBaseUserGrpcService.getOrganization(currentToken.getOrgId());
        if (Objects.isNull(organization)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应租户下的企业钱包id信息");
        }

        // 获取钱包占用金额
        List<Integer> freezeTypes = new ArrayList<>();
        freezeTypes.add(FreezeTypeEnum.RED_PACKET.getType());
        freezeTypes.add(FreezeTypeEnum.SMS.getType());
        List<WalletFreezeInfoVO> list = walletWalletGrpcService.getWalletFreeze(organization.getCorpWallet(), freezeTypes);
        return XmResultJson.success(list);
    }

    /**
     * 企业钱包-【消费:[红包发放、短信消费、版本购买]、发票:[未开票、开票中、已开票]】界面金额查询
     *
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/20 20:57
     */
    @GetMapping("/corporate_wallet/expenses/")
    public XmResultJson<ExpenseInfoDTO> getWalletExpenses() {
        // 获取当前的登录信息
        TokenDTO currentToken = SecurityContextHolder.getToken();
        // 根据orgId查询租户的企业钱包id
        OrganizationDTO organization = walletBaseUserGrpcService.getOrganization(currentToken.getOrgId());
        if (Objects.isNull(organization)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应租户下的企业钱包id信息");
        }

        // 获取企业消费信息、开票信息
        ExpenseInfoDTO expenseInfoDTO = walletExpenseGrpcService.getWalletExpenses(organization.getCorpWallet());
        return XmResultJson.success(expenseInfoDTO);
    }

    /**
     * 企业钱包-余额-充值
     *
     * @param vo 请求信息
     * @return XmResultJson<WalletRechargeVO>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/5/16 11:12
     */
    @PostMapping("/corporate_wallet/recharge/")
    @XmAuth
    public XmResultJson<WalletRechargeVO> rechargeWallet(@RequestBody WalletRechargeRequestVO vo) {
        // 获取用户认证信息
        TokenDTO tokenDTO = SecurityContextHolder.getToken();
        // 钱包余额充值
        ServiceResult<WalletRechargeInfoDTO> result = limitOrderService.rechargeWallet(limitOrderConvert.walletRechargeVo2Dto(vo), tokenDTO);
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(limitOrderConvert.walletRechargeInfoDto2Vo(result.getData()));
    }

    /**
     * 获取钱包充值订单的状态
     *
     * @param orderId 订单Id
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.wallet.grpc.client.dto.RechargeInfoDTO>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/20 23:21
     */
    @GetMapping("/corporate_wallet/get_recharge_order/")
    @XmAuth
    public XmResultJson<RechargeInfoDTO> getRechargeOrder(@RequestParam(name = "order_id") String orderId) {
        RechargeInfoDTO rechargeOrder = walletWalletGrpcService.getRechargeOrder(orderId);
        if (Objects.isNull(rechargeOrder)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.THIRD_PART, "获取钱包充值订单的状态失败");
        }
        return XmResultJson.success(rechargeOrder);
    }

    /**
     * 获取限制充值订单的状态
     *
     * @param limitOrderId 限制充值订单id
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.wallet.controller.vo.response.RechargeInfoVO>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/5/16 19:11
     */
    @XmAuth
    @GetMapping("/corporate_wallet/get_recharge_limit_order/")
    public XmResultJson<RechargeInfoVO> getRechargeLimitOrder(@RequestParam(name = "order_id") String limitOrderId) {
        // 获取用户认证信息
        TokenDTO tokenDTO = SecurityContextHolder.getToken();
        // 查询限制充值订单
        ServiceResult<LimitOrderDTO> result = limitOrderService.getByIdAndOrgId(limitOrderId, tokenDTO.getOrgId());
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功,设置返回值
        RechargeInfoVO rechargeInfoVO = null;
        if (result.getData() != null) {
            LimitOrderDTO limitOrderDTO = result.getData();
            rechargeInfoVO = limitOrderConvert.dto2RechargeInfoVo(limitOrderDTO);
            rechargeInfoVO.setRechargeLimit(OrgWalletConfigRechargeLimitEnum.ONLY_ORG_ACCOUNT.getType());
            rechargeInfoVO.setAmount(limitOrderDTO.getAmount() != null ?
                    limitOrderDTO.getAmount().multiply(CommonConstant.WALLET_RECHARGE_MONEY_DIVIDED).intValue() : null);
            rechargeInfoVO.setFee(limitOrderDTO.getFee() != null ?
                    limitOrderDTO.getFee().multiply(CommonConstant.WALLET_RECHARGE_MONEY_DIVIDED).intValue() : null);
        }
        return XmResultJson.success(rechargeInfoVO);
    }

    /**
     * 根据id查询发票信息
     * 企业管理后台获取开票记录
     * 暂时没有筛选，所以暂时只需要分页
     * is_admin: 为true的时候为财务查询，false的为企业查询
     * apps_mysql/wallet/v2/invoice/handlers.py:93
     * <p>
     * python引用：apps_mysql.wallet.v2.wallet.handlers.CorporateWalletRecordsHandler.get
     * * - “@decorators.render_json“
     * * - ”@decorators.permission”
     *
     * @param id 发票记录id
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.wallet.controller.vo.response.InvoiceRecordsResponseVO>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/05/14 18:26
     */
    @GetMapping("/invoice/v2/info/{id}")
    public XmResultJson<InvoiceRecordsResponseVO> getInvoice(@PathVariable("id") Integer id) {
        // 直接根据id查询发票信息
        InvoiceDTO invoice = walletInvoiceGrpcService.getInvoice(id);
        if (Objects.isNull(invoice)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应的发票申请信息");
        }
        InvoiceRecordsResponseVO response = walletWalletConvert.invoiceDto2Vo(invoice);
        return XmResultJson.success(response);
    }

    /**
     * 分页查询发票信息列表
     * 企业管理后台获取开票记录
     * 暂时没有筛选，所以暂时只需要分页
     * is_admin: 为true的时候为财务查询，false的为企业查询
     * <p>
     * python引用：apps_mysql/wallet/v2/invoice/handlers.py:93
     * * - “@decorators.render_json“
     * * - ”@decorators.permission”
     *
     * @param page     第几页，默认不传第一页
     * @param pageSize 每页大小，默认不传为10
     * @return com.bestcem.xm.util.XmResultJson
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/19 14:21
     */
    @GetMapping("/invoice/v2/info/")
    public XmResultJson<PageInvoiceRecordsResponseVO> listInvoice(@RequestParam("page") Integer page,
                                                                  @RequestParam("rowsPerPage") Integer pageSize) {
        // 获取当前的登录信息
        TokenDTO currentToken = SecurityContextHolder.getToken();

        // 参数构建
        InvoiceRecordsRequestDTO.InvoiceRecordsRequestDTOBuilder builder = InvoiceRecordsRequestDTO.builder();
        builder.adminFlag(false);
        builder.pageFlag(true);
        builder.orgId(currentToken.getOrgId());
        builder.page(page);
        builder.size(pageSize);

        // 获取发票申请记录
        ListInvoiceDTO listInvoiceDTO = walletInvoiceGrpcService.listInvoices(builder.build());
        if (Objects.isNull(listInvoiceDTO)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应的发票申请列表信息");
        }

        // 转换结果
        PageInvoiceRecordsResponseVO response = new PageInvoiceRecordsResponseVO();
        response.setTotal((long) listInvoiceDTO.getTotal());
        response.setRows(walletWalletConvert.invoiceDtos2Vos(listInvoiceDTO.getInvoices()));
        return XmResultJson.success(response);
    }

    /**
     * 创建发票，提交发票信息
     * python引用：apps_mysql.wallet.v2.invoice.handlers.InvoiceHandler.post
     * * - “@decorators.render_json“
     * * - ”@decorators.permission”
     *
     * @param request        请求参数信息
     * @param servletRequest http请求信息
     * @return com.bestcem.xm.util.XmResultJson<java.lang.String>
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/19 14:49
     */
    @PostMapping("/invoice/v2/info/")
    public XmResultJson<String> applyInvoice(@RequestBody @Valid ApplyInvoiceRequestVO request, HttpServletRequest servletRequest) {
        // 获取当前的登录信息
        TokenDTO currentToken = SecurityContextHolder.getToken();
        // 邮箱校验
        String email = request.getRecipient().getEmail();
        Boolean validateEmail = EmailUtil.validateEmail(email);
        if (!Boolean.TRUE.equals(validateEmail)) {
            return XmResultJson.fail(ValidationErrorCodeEnum.EMAIL_ERROR, "Email format error");
        }

        // 参数校验
        InvoiceTypeEnum invoiceType = InvoiceTypeEnum.getByType(request.getDetail().getType());
        if (Objects.isNull(invoiceType)) {
            return XmResultJson.fail(ReqErrorCodeEnum.PARAM_RANGE, "The 'type' not allowed !");
        }
        if (!InvoiceTypeEnum.SPECIAL_VAT.equals(invoiceType)) {
            request.setCompany(new CompanyDTO());
        }
        request.setOrgId(currentToken.getOrgId());

        // 根据orgId查询租户的企业钱包id
        OrganizationDTO organization = walletBaseUserGrpcService.getOrganization(currentToken.getOrgId());
        if (Objects.isNull(organization)) {
            return XmResultJson.fail(ResourceErrorCodeEnum.NOT_FOUND, "未查询到对应租户下的企业钱包id信息");
        }

        // 获取企业消费信息、开票信息
        ExpenseInfoDTO expenseInfoDTO = walletExpenseGrpcService.getWalletExpenses(organization.getCorpWallet());
        if (request.getDetail().getAmount().compareTo(expenseInfoDTO.getNotInvoicedAmount()) > 0) {
            return XmResultJson.fail(ReqErrorCodeEnum.PARAM_RANGE, "开票金额大于未开票金额");
        }

        request.setWalletId(organization.getCorpWallet());
        Integer innerFlag = organization.getInnerFlag();

        // 创建发票信息
        InvoiceDTO invoice = walletInvoiceGrpcService.createInvoice(walletWalletConvert.applyInvoiceVo2Dto(request));
        if (Objects.isNull(invoice)) {
            return XmResultJson.fail(ReqErrorCodeEnum.PARAM_RANGE, "创建发票信息失败");
        }

        /*
         * 发送邮件通知
         */
        // 1. grpc获取收件人
        Integer type = Integer.valueOf(1).equals(innerFlag) ? InvoiceNotifyEmailTypeEnum.TEST.getType() : InvoiceNotifyEmailTypeEnum.REAL.getType();
        List<String> emails = walletOmUserGrpcService.getOmEmailConfig(OmEmailType.INVOICE.getType(), type);
        if (Objects.isNull(emails)) {
            log.error("申请发票，发送邮件通知失败，未从grpc接口中获得om配置的发票收件人邮箱列表信息！");
            return XmResultJson.success(invoice.getDisplayId());
        }
        // 2. grpc获取orgUrl
        String corpUrl = envSettingUtil.getCorpUrl("", "", "", "");
        String subject = "收到倍市得发票申请（抬头：" + request.getDetail().getTitle() + "）";
        String content = "收到倍市得发票申请（ID：" + invoice.getDisplayId() + "），请登录 " + corpUrl + "/company/invoices/main 查看。";
        walletAsyncUtil.sendMailAsync(emails.toArray(new String[]{}), subject, content);

        SmsMessage smsMessage = new SmsMessage();
        smsMessage.setContent(content)
                .setName("发票申请")
                .setOrgId(currentToken.getOrgId())
                .setReceiver(String.join(",", emails))
                .setSender("")
                .setType(NotifyTypeEnum.EMAIL.getType())
                .setStatus(NotifyStatusEnum.IS_SEND.getType())
                .setSendTime(new SimpleDateFormat(DateUtil.NORM_DATETIME_PATTERN).format(DataBaseUtil.getDate()));

        // 发送MQ
        //userMessageSender.publishOmSmsSyc(smsMessage);

        return XmResultJson.success(invoice.getDisplayId());
    }

    /**
     * 钱包余额充值-小程序 限制充值订单
     *
     * @param limitRechargeVO 下单参数
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.wallet.controller.vo.response.RechargeInfoVO>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/5/17 10:11
     */
    @XmAuth
    @PostMapping("/corporate_wallet/recharge_limit/")
    public XmResultJson<WalletLimitRechargeVO> rechargeLimit(@RequestBody LimitRechargeVO limitRechargeVO) {
        // 校验参数
        if (StringUtils.isBlank(limitRechargeVO.getLimitOrderId())) {
            XmResultJson.fail(ReqErrorCodeEnum.PARAM_LOST, "order_id cannot be blank");
        }
        if (StringUtils.isBlank(limitRechargeVO.getOpenId())) {
            XmResultJson.fail(ReqErrorCodeEnum.PARAM_LOST, "open_id cannot be blank");
        }
        // 获取用户认证信息
        TokenDTO tokenDTO = SecurityContextHolder.getToken();
        // 企业钱包小程序充值订单下单
        ServiceResult<MiniProgramPayDTO> result = limitOrderService
                .rechargeLimitWallet(limitRechargeVO.getLimitOrderId(), limitRechargeVO.getOpenId(), tokenDTO);
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(limitOrderConvert.convert(result.getData()), Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功,设置返回值
        return XmResultJson.success(limitOrderConvert.convert(result.getData()));
    }

}
